﻿// Demo2.cpp : 定义应用程序的入口点。
//

#include "framework.h"
#include "Demo2.h"
#include "geo/Cube.h"

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	WinFunc::CreateConsole();

	// TODO: 在此处放置代码。
	Demo2 myApp;
	myApp.Init(hInstance, 800, 640, "demo2");
	myApp.StartMainLoop();
	return 0;
}

void Demo2::OnResize()
{
	float aspect = (float)GetWidth() / GetHeight();
	mCamera.UpdateAspect(aspect);
}

void Demo2::OnInit()
{
	auto device = m_graphics->GetDevice();
	auto ctx = m_graphics->GetDeviceContext();

	// init camera
	float aspect = (float)GetWidth() / GetHeight();
	mCamera.SetPerspective(Deg2Rad(60), aspect, 0.1f, 1000.0f);
	mCamera.SetLookAt(Vec3(0, 1, -5), Vec3::Zero(), Vec3::AxisY());

	// 创建一个 cube
	mMeshData0.InitFromIndexedTriangleList(Cube::Make());
	mVertexShader = std::make_shared<VertexShader>("hlsl/first.hlsl", "VS_Main");
	mPixelShader = std::make_shared<PixelShader>("hlsl/first.hlsl", "PS_Main");

	mInstanceVertexShader = std::make_shared<VertexShader>("hlsl/instance.hlsl", "VS_Main");
	mInstancePixelShader = std::make_shared<PixelShader>("hlsl/instance.hlsl", "PS_Main");

	// 创建 gameobject
	for (size_t i = 0; i < 1; i++)
	{
		auto obj = std::make_shared<GameObject>();
		obj->SetShader(mVertexShader.get(), mPixelShader.get());
		obj->SetMesh_Pos(mMeshData0);
		mObjs.push_back(obj);
	}

	// 创建 objInstance
	mObjInstance = std::make_shared<GameObject>();
	mObjInstance->SetShader(mInstanceVertexShader.get(), mInstancePixelShader.get());
	mObjInstance->SetInstanceMesh_Pos(mMeshData0);


	// constant buffer
	{
		CreateConstantBuffer<BufPerFrameData>(mDxBufPerFrame.GetAddressOf());
		CreateConstantBuffer<BufPerObjectData>(mDxBufPerObject.GetAddressOf());

		// 正常的 shader
		ctx->VSSetShader(mVertexShader->GetDxVertexShader(), nullptr, 0);
		ctx->VSSetConstantBuffers(0, 1, mDxBufPerFrame.GetAddressOf());
		ctx->VSSetConstantBuffers(1, 1, mDxBufPerObject.GetAddressOf());
		ctx->PSSetShader(mPixelShader->GetDxPixelShader(), nullptr, 0);

		//  instance shader
		ctx->VSSetShader(mInstanceVertexShader->GetDxVertexShader(), nullptr, 0);
		ctx->VSSetConstantBuffers(0, 1, mDxBufPerFrame.GetAddressOf());
		ctx->PSSetShader(mInstancePixelShader->GetDxPixelShader(), nullptr, 0);
	}

	// 创建10个
	for (int i = 0; i < 10; i++)
	{
		auto t = std::make_shared<Transform>();

		/*float x = RandomFloat(-50, 50);
		float y = RandomFloat(-12, 12);
		float z = RandomFloat(-50, 50);*/
		float x = -10 + i * 2;
		float y = 2;
		float z = 10;
		t->SetLocalPosition(x, y, z);

		//// 随机一个角度出来
		//float roll = RandomFloat(0, 3.14f);
		//float pitch = RandomFloat(0, 3.14f);
		//float yaw = RandomFloat(0, 3.14f);
		//t->SetLocalRotation(Quaternion::CreateFromRollPitchYaw(roll, pitch, yaw));

		//// 缩放
		//float sx = RandomFloat(0.5f, 2);
		//t->SetLocalScale(Vec3(sx, sx, sx));

		mTransformVec.push_back(t);
	}
}

void Demo2::OnGUI()
{
	//TODO:
}

void Demo2::OnInput()
{
}

void Demo2::OnUpdate()
{
	// 更新每帧更新的buffer,矩阵注意转置
	auto ctx = m_graphics->GetDeviceContext();
	mBufPerFrameData.projMat = mCamera.GetProjMatrix().Transpose();
	mBufPerFrameData.viewMat = mCamera.GetViewMatrix().Transpose();

	D3D11_MAPPED_SUBRESOURCE mappedData;
	D_HRESULT(ctx->Map(mDxBufPerFrame.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
	memcpy_s(mappedData.pData, sizeof(BufPerFrameData), &mBufPerFrameData, sizeof(BufPerFrameData));
	ctx->Unmap(mDxBufPerFrame.Get(), 0);

	// 更新物体的角度
	static float yaw = 0;
	static float dyaw = 0.001f;
	yaw += dyaw;
	for (auto& obj : mObjs) {
		obj->GetTransform().SetLocalRotation(Quaternion::RotateY(yaw));
	}

	// 更新实例的角度
	for (auto& t : mTransformVec) {
		//TODO:
	}
}

void Demo2::OnFrame()
{
	// 
	auto ctx = m_graphics->GetDeviceContext();
	m_graphics->ClearBuffer();

	// 绘制物体
	for (auto& obj : mObjs) {

		// 更新 constant buffer
		mBufPerObjectData.worldMat = obj->GetTransform().GetLocalMatrix().Transpose();
		D3D11_MAPPED_SUBRESOURCE mappedData;
		D_HRESULT(ctx->Map(mDxBufPerObject.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
		memcpy_s(mappedData.pData, sizeof(BufPerObjectData), &mBufPerObjectData, sizeof(BufPerObjectData));
		ctx->Unmap(mDxBufPerObject.Get(), 0);

		obj->Draw();
	}

	// 绘制实例
	mObjInstance->DrawInstance(mTransformVec);
}

void Demo2::OnTerminate()
{
}
